﻿#ifndef GY_TREEVIEW_H
#define GY_TREEVIEW_H

#include "GY_ControlLibrary_global.h"
#include <QStandardItem>
#include <QTreeView>

class GY_CONTROLLIBRARY_EXPORT GY_TreeView : public QTreeView
{
    Q_OBJECT
public:
    explicit GY_TreeView(QWidget *parent = nullptr);

    //-----------------------------列编辑接口--------------------------------------
    /**
     * @brief setColumnCount 设置列数
     * @param columnCount 添加的列数
     */
    void setColumnCount(const int columnCount);
    /**
     * @brief addColumn 添加列数
     * @param columnName 添加的列名
     */
    void addColumn(const QString &columnNmae);
    /**
     * @brief insterColumn 插入列
     * @param index 插入在第几列
     * @param columnName 插入的列名
     * @return 返回插入列是否成功
     */
    bool insterColumn(const int index, const QString &columnName);
    /**
     * @brief deleteColumn 删除列
     * @param index 删除的第几列
     * @return 返回删除列是否成功
     */
    bool deleteColumn(const int index);
    /**
     * @brief setColumnHeadName  修改列名
     * @param nameList  要修改的列名集
     */
    void setColumnHeadName(const QStringList &nameList);
    /**
     * @brief setColumnHeadName  修改某一列列名
     * @param index  要修改名字在第几列
     * @param headName  要修改成的名字
     */
    void setColumnHeadName(const int index,const QString &headName);

    //------------------------------行编辑接口---------------------------------------
    /**
     * @brief addRowData  添加行数据
     * @param id 行Id
     * @param rowData 行数据
     * @param nodeParentId 父级Id
     * @return 返回添加是否成功
     */
    bool addRowData(const QVariant &id, const QVector<QVariant>&rowData, const QVariant &nodeParentId=QVariant(), const QVariant iconType=QVariant());
    /**
     * @brief insterRowData   插入行数据
     * @param rowId 节点id
     * @param rowData 插入的行数据
     * @param index 引索第几个
     * @param nodeParentId 父级Id
     * @return 返回插入行数据是否成功
     */
    bool insterRowData(const QVariant &id, const QVector<QVariant>&rowData,const int index, const QVariant &nodeParentId=QVariant(), const QVariant iconType=QVariant());
    /**
     * @brief deleteRow  删除指定行
     * @param id 删除行的id号
     * @return 返回删除是否成功
     */
    bool deleteRow(const QVariant &id);
    /**
     * @brief clearData 清除所有数据
     */
    void clearData();
    /**
     * @brief setRowData  修改行数据
     * @param rowId  修改行id
     * @param rowData  要修改的数据
     * @return 是否修改成功
     */
    bool setRowData(const QVariant &id, const QVector<QVariant>&rowData);
    /**
     * @brief setCellData  修改单元格数据
     * @param id  修改的行id
     * @param columnIndex  修改第几列
     * @param cellData  要修改的数据
     * @return 是否修改成功
     */
    bool setCellData(const QVariant &id, const int columnIndex, const QVariant &cellData);
    /**
     * @brief getRowData  通过id获取行数据
     * @param id 要获取的节点id
     * @return 返回id对应的行数据
     */
    QVector<QVariant> getRowData(const QVariant &id);
    /**
     * @brief getRowData  通过parentId获取行数据
     * @param index  索引要获取第几行
     * @param parentId  父节点id
     * @return 索引的行数据
     */
    QVector<QVariant> getRowDatas(const int index, const QVariant &parentId=QVariant());
    /**
     * @brief getCellData  获取单元格数据
     * @param id  节点id
     * @param columnIndex  索引第几列
     * @param data  单元格的数据
     * @return 返回是否获取成功
     */
    bool getCellData(const QVariant &id, const int columnIndex, QVariant &data);

    //-----------------------------图标类型接口--------------------------------------
    /**
     * @brief addIconType 添加图标类型
     * @param iconType 图标类型
     * @param icon 图标
     * @return 是否添加成功
     */
    bool addIconType(const QVariant &iconType, const QIcon &icon);
    /**
     * @brief setNodeIconType 设置行id对应的图标
     * @param id 行id
     * @param iconType 图标类型
     * @return 是否设置成功
     */
    bool setNodeIconType(const QVariant &id, const QVariant &iconType);

    //-----------------------------选择接口------------------------------------------
    /**
     * @brief getSelecRowId  获取选择行id
     * @return  多选下返回选中的第一行
     */
    QVariant getSelectRowId();
    /**
     * @brief getSelectRowIds 获取选择行id
     * @return  单选时返回一个id
     */
    QVector<QVariant> getSelectRowIds();
    /**
     * @brief setRowSelectState 设置行选择状态
     * @param rowId 节点ID
     * @param isSelect 该行是否选择
     * @return 是否设置成功
     */
    bool setRowSelectState(const QVariant &rowId,const bool isSelect);

    //-----------------------------展开接口-----------------------------------------
    /**
     * @brief setRowExpendState 设置行展开模式
     * @param rowId  第几个id
     * @param isExpend 是否展开
     * @return 是否展开该行
     */
    bool setRowExpendState(QVariant rowId, bool isExpend);

    /**
     * @brief treeAllChildExpend 所有子节点展开
     * @param pItem 子节点的item
     * @param isExpend 是否展开
     */
    void treeAllChildExpend(QStandardItem *pItem, bool isExpend);

    /**
     * @brief treeTopPareentExpent 递归至顶层父节点
     * @param pItem 父节点item
     * @param isExpend 是否展开
     */
    void treeTopPareentExpent(QStandardItem *pItem, bool isExpend);

    //-----------------------------复选框接口-----------------------------------------
    /**
     * @brief setIsChecked  设置是否显示复选框
     * @param isChecked  是否勾选
     */
    void setIsChecked(const bool isChecked);
    /**
     * @brief getIsChecked 获取当前是否显示复选框
     * @return 返回是否显示复选框
     */
    bool getIsChecked();
    /**
     * @brief getCheckedRowIds  获取选中的行id
     * @return 返回全部id
     */
    QVector<QVariant> getCheckedRowIds();
    /**
     * @brief getCheckRowDatas  获取选中行数据
     * @return 返回行数据集
     */
    QMap<QVariant,QVector<QVariant>> getCheckRowDatas();
    /**
     * @brief setRowCheckState  设置复选框选中行状态
     * @param rowId  节点id
     * @param isCheck  是否选中
     * @return 返回该行是否被选中，true选中，false未被选中
     */
    bool setRowCheckState(const QVariant &rowId,const bool isCheck);
    /**
     * @brief setTreeAllChecked 复选框全选/全不选
     * @param check 是否全选/全不选
     */
    void setTreeAllChecked(bool isCheck);
    /**
     * @brief setTreeAllChildChecked  设置子节点全选/全不选
     * @param pItem 对应的item
     * @param check 是否勾选
     */
    void setTreeAllChildChecked(QStandardItem *pItem, bool check);
    /**
     * @brief treeCheckChildChanged  根据子节点改变，更改父节点
     * @param pItem 对应的item
     */
    void treeCheckChildChanged(QStandardItem *pItem);
    /**
     * @brief checkSibling  检测兄弟节点情况
     * @param pItem 对应的item
     * @return 返回勾选状态
     */
    Qt::CheckState checkSibling(QStandardItem *pItem);
    /**
     * @brief itemFindId 根据item查找对应的id
     * @param pItem 对应的item
     * @return 返回item对应的id
     */
    QVariant itemFindId(QStandardItem *pItem);

protected:
    /**
     * @brief mousePressEvent 鼠标单击空白事件
     * @param event 点击事件
     */
    void mousePressEvent(QMouseEvent* event);
    /**
     * @brief getAllChildChecked 设置所有节点的选择状态
     * @param pItem 子节点是item
     */
    void getAllChildChecked(QStandardItem* const pItem,const bool isChecked);
    /**
     * @brief moveItems 将旧列表items赋给新列表
     * @param pDetItem 目的item
     * @param pSrcItem 源item
     * @param columnCount 目的列表列数
     */
    void moveItems(QStandardItem* const pDetItem,const QStandardItem* pSrcItem,const int columnCount);
    /**
     * @brief insertChildColumn 循环插入空白列
     * @param pItem 每行的item
     */
    void insertChildColumn(const int index, QStandardItem* const pItem);
    /**
     * @brief deleteChildColumn  循环删除指定列
     * @param index  索引删除第几列
     * @param pItem  每行对应的item
     */
    void deleteChildColumn(const int index, QStandardItem* const pItem);

private slots:
    /**
     * @brief receiveClicked 单击接收事件
     * @param index 当前index
     */
    void receiveClicked(const QModelIndex &index);

    //--------------------------------事件信号------------------------------------------
signals:
    /**
     * @brief selectChangeEvent 选择行改变信号，当行号发生改变时，发送信号
     * @param selectId 改变的id
     */
    void selectChangeEvent(const QVariant selectId);
    /**
     * @brief selectChangeEvent 选择行改变信号
     * @param index  索引第几行
     * @param parentId  父节点id
     */
    void selectChangeEvent(const int index, const QVariant parentId);
    /**
     * @brief checkStateChangeEvent  复选框选中状态更改信号，当复选框勾选状态发生改变，发送信号
     * @param checkRowId 勾选的行id
     */
    void checkStateChangeEvent(const QVariant checkRowId);

private:
    QStandardItemModel *m_pModel; //标准项目模型
    bool m_isCheckable;

    /**
     * @brief The Tree_Node_Info struct
     * 树节点信息
     */
    struct Tree_Node_Info
    {
        QVariant nodeId; //节点ID
        QVariant nodeParentId; //父节点ID
        QStandardItem* pNodeItem; //节点控件指针
        QVector<QVariant> nodeDatas; //节点数据
    };
    QMap<QVariant,Tree_Node_Info*> m_TreeNodeInfo; //节点信息表
    QMap<QVariant,QIcon> m_IconTypeMap; //类型和图标表
    QMap<QVariant,QIcon> m_IconIdMap; //节点和图标表

    QVector<QVariant> m_checkedRowIds; //选中的行id
    QMap<QVariant, QVector<QVariant>> m_checkRowDatas; //选中行数据表
    QVariant m_selectRowId; //选择的id
    QVariant m_checkedId; //勾选中的id
    QVariant m_expendId; //展开的id

    QVector<QVariant> m_getselectRowIdsVec; //获取选择行id

};

#endif // GY_TREEVIEW_H
